home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Maclife 157
/
MACLIFE157-2001-09.ISO.7z
/
MACLIFE157-2001-09.ISO
/
Linux
/
MacOS Tools
/
Other
/
BootX 1.1.3 (for Old Mac OS)
/
Sources
/
src
/
BootX.c
< prev
next >
Wrap
C/C++ Source or Header
|
2001-07-23
|
70KB
|
2,794 lines
/* BootX
*
* Written by Benjamin Herrenschmidt
*
* portions of this code from InfiniteOS boot loader by <...>, portions from
* quik by Paul Mackerras.
*
* GPL....
*
*
* To do:
*
* - Add menu for pre-configured settings
*/
#include <Devices.h>
#include <Files.h>
#include <DriverServices.h>
#include <PEFBinaryFormat.h>
#include <ShutDown.h>
#include <Dialogs.h>
#include <Windows.h>
#include <Menus.h>
#include <LowMem.h>
#include <DiskInit.h>
#include <Processes.h>
#include <TextUtils.h>
#include <Resources.h>
#include <AppleEvents.h>
#include <AEDataModel.h>
#include <Folders.h>
#include <ToolUtils.h>
#include <SCSI.h>
#include <Gestalt.h>
#include <Packages.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#ifndef macintosh
#define macintosh
#endif
#ifndef BOOTX_BUILD_INIT
#define BOOTX_BUILD_INIT 0
#endif
/* BootX trace is not supported in this version */
#ifndef BOOTX_TRACE
#define BOOTX_TRACE 0
#endif
#ifndef BOOTX_LOG_MAP
#define BOOTX_LOG_MAP 0
#endif
/* This option reverts to old bootx behaviour: the kernel is entered
directly, without turnig OFF the MMU. */
#ifndef NO_BOOTSTRAP
#define NO_BOOTSTRAP 0
#endif
#include "BootX.h"
#include "DeviceTree.h"
#include "LowLevelBoot.h"
#include "ErrorCodes.h"
#include "elf_loader_defs.h"
#include "MoreFiles.h"
#include "MoreFilesExtras.h"
#include "IterateDirectory.h"
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
#define NAME_REGISTRY_MAX_SIZE (200UL * 1024UL) // 200Kb: Size pre-allocated for holding name registry
#define BOOT_KERNEL_STACK_SIZE 65536 // initial stack
#define PAGE_ALIGN(x) ((((UInt32)(x)) + g_page_size - 1) & (-g_page_size))
#define LINE_ALIGN(x) ((((UInt32)(x)) + 32 - 1) & (-32))
#define BI_OFFSET(x) (g_stuff_offsets[x] - g_stuff_offsets[offset_bootinfo])
/* Indexes in offset array */
enum
{
offset_kernel = 0, /* kernel itself, offset 0 */
offset_stack, /* boot stack */
offset_bootinfo, /* boot_info */
offset_arguments, /* args line */
offset_color_map, /* colormap setup by bootx */
offset_device_tree, /* device tree */
offset_ramdisk, /* optional ramdisk */
offset_unmangler, /* unmangler (may be moved higher) */
offset_count
};
#define DEBUG_ERR(err,msg) display_error((err), msg, __FILE__, __LINE__)
#if BOOTX_LOG_MAP
static void open_log_file(void);
static void close_log_file(void);
static void log_printf(const char *fmt, ...);
#endif
#if BOOTX_BUILD_INIT
/* Procinfo of entry point */
ProcInfoType __procinfo = kPascalStackBased;
#endif
/* Dialog items IDs */
enum
{
button_boot_linux = 2,
button_boot_macos = 3,
field_kernel_args = 5,
field_root_device = 6,
button_set_default = 7,
text_status_display = 9,
check_use_ram_disk = 11,
check_video_of_only = 12,
button_boot_mklinux = 15,
check_set_l2cr = 16,
menu_kernels = 17
};
/* Resources */
enum
{
string_kernel_names = 128,
string_ramdisk_names = 129,
string_kernel_args = 130,
string_prefs_file_names = 131,
string_boot_delay = 132,
string_mkboot_names = 133,
string_mkboot_patch = 134,
string_kernel_folder = 135,
string_mkboot_patched = 257,
text_mkboot_fake_prefs = 128,
dialog_main = 131,
alert_error = 130,
code_boot_glue68k = 128,
code_boot_gluePPC = 129,
menu_kernel_list = 1000
};
/* Boot choice */
enum
{
boot_macos = 0,
boot_linux,
boot_mklinux,
boot_choice_count = 3
};
static short g_boot_choices[boot_choice_count][2] =
{
button_boot_macos , 1,
button_boot_linux , 0,
button_boot_mklinux , 0
};
/* Struct used for mount event queue */
typedef struct saved_mount
{
QElem link;
UInt32 message;
} saved_mount_t;
/* An item in the kernel list. Note that an empty name
means a separator item */
typedef struct kernel_item
{
FSSpec file;
short menu_item;
UInt32 file_size;
UInt32 offset;
UInt32 mem_size;
UInt32 entry;
short file_ref;
} kernel_item_t;
#define MAX_KERNEL_ITEMS 32
/* MacOS nanokernel data structures */
#define MACOS_MEMMAP_PTR_ADDR 0x5FFFEFF0
#define MACOS_MEMMAP_SIZE_ADDR 0x5FFFEFF6
#define MACOS_MEMMAP_BANK_0FFSET 48
/* Preferences */
#define BOOTX_PREFS_VERSION 4
#define BOOTX_PREFS_COMPATIBLE_VERSION 1
#pragma options align=power
typedef struct bootx_prefs
{
/* Version of this structure */
unsigned long version;
/* backward compatible down to version: */
unsigned long compatible_version;
unsigned char boot_choice; // uchar for compatibility
Boolean use_ramdisk;
Boolean video_of_only;
Boolean use_l2cr_settings;
Boolean unused_boolean[4];
Str255 command_line;
Str32 root_device;
Str63 kernel_name;
} bootx_prefs, **bootx_prefs_handle;
#pragma options align=reset
/* Generic tools */
inline void
pstrcpy(Str255 dst, ConstStr255Param src)
{
memcpy(dst, src, src[0] + 1);
}
inline void
pstrncpy(Str255 dst, ConstStr255Param src, unsigned long max_size)
{
unsigned char l = (src[0] > max_size) ?
max_size : src[0]; memcpy(dst, src, l+1);
dst[0] = l;
}
inline void
pstrcat(Str255 dst, ConstStr255Param append)
{
int size = append[0];
if ((dst[0] + size) > 255)
size = 255 - dst[0];
memcpy(&dst[dst[0]+1], &append[1], size);
dst[0] += size;
}
/* --- Prototypes -------------------------------------- */
typedef void (*iterate_device_proc)(RegEntryIDPtr entryID);
pascal void main(void);
static OSErr make_resident(void* ptr, unsigned long size, Boolean contiguous);
static UInt8* get_physical(void* ptr);
static OSErr check_kernel(kernel_item_t* kern_infos, Boolean will_load);
static void* load_bootstrap(long mapsize, UInt32** outMapBegin, UInt32 *outTotalSize);
static OSErr load_kernel(kernel_item_t* kern_infos, UInt8* loc);
static UInt32 get_temp_page(UInt32 *cur_temp, UInt32 *used_map, UInt32 used_size);
static OSErr make_kernel_map(UInt32 **out_map, UInt32 *out_size);
static void init_macos_toolbox(void);
static Boolean create_dialog(void);
static void dispose_dialog(void);
static void prepare_and_boot(kernel_item_t* kern_infos);
static Boolean locate_ramdisk(void);
static void setup_default_buttons(void);
static void display_error(OSErr err, int msg, char *file, int line);
static void get_options_from_dialog(void);
static OSErr open_ramdisk(FSSpec *ramdiskSpec);
static OSErr load_ramdisk(UInt8* loc);
static OSErr locate_file(short namesResourceID, OSType defaultFolder, FSSpecPtr outSpec);
static void load_prefs(void);
static void save_prefs(void);
static void do_boot_mklinux(void);
static Boolean locate_mklinux(void);
static OSErr build_pci_device_tree(Ptr* outDevTree, UInt32 *outDevTreeSize, UInt32 *outDispRegOff);
static void build_memory_map(void);
static void lookup_kernels(void);
static pascal void kernel_iterate_filter_proc( const CInfoPBRec* const cpbPtr,
Boolean *quitFlag,
void* yourDataPtr);
static void build_kernels_menu(void);
static void add_l2cr_property(UInt32 l2cr_value);
static void check_burgundy_patch(void);
#if !BOOTX_BUILD_INIT
static OSErr send_restart_to_finder(void);
static OSErr find_finder_process(ProcessSerialNumberPtr processSN);
#else
static Ptr alloc_high_mem(unsigned long count);
static void save_mount_event(EventRecord *event);
static void resend_mount_events(void);
#endif
// CFM stuffs
pascal OSErr FragmentInitialize(const CFragInitBlockPtr initInfo);
pascal void FragmentTerminate(void);
pascal OSErr __initialize(const CFragInitBlockPtr initInfo);
pascal void __terminate(void);
/* --- Globals ----------------------------------------- */
static UInt8* g_stuff;
static Ptr g_stuff_ptr;
static UInt32 g_stuff_offsets[offset_count];
static boot_infos_t* g_boot_infos;
static Boolean g_use_ramdisk;
static ControlHandle g_use_ramdisk_cntl;
static void* g_ramdisk;
static UInt32 g_ramdisk_size;
static short g_ramdisk_ref;
static Boolean g_video_of_only;
static ControlHandle g_video_of_only_cntl;
static DialogPtr g_dialog;
static Str255 g_kernel_args;
static THz g_my_zone;
static FSSpec g_kernel_spec;
static FSSpec g_ramdisk_spec;
static FSSpec g_mkboot_spec;
static Boolean g_have_ramdisk;
static int g_current_choice;
static UInt32 g_entry_ticks;
static UInt32 g_autoboot_delay;
static Handle g_status_item;
static QHdr g_mount_queue;
static Boolean g_vm_present;
static UInt32 g_page_size;
static Boolean g_L2CR_pref;
static Boolean g_L2CR_set;
static Boolean g_L2CR_available;
static UInt32 g_L2CR_value;
static ControlHandle g_set_L2CR_cntl;
static Boolean g_arch_PCI;
static UInt32 g_load_base = 0;
static ControlHandle g_kernel_menu = NULL;
static kernel_item_t g_kernel_items[MAX_KERNEL_ITEMS];
static UInt32 g_kernel_items_count = 0;
static UInt32 g_kernel_items_choice = 0;
#if !BOOTX_BUILD_INIT
static FSSpec g_application_spec;
#endif
static RGBColor g_back_color = {0xEEEE, 0xEEEE, 0xEEEE};
/* --- Implementation ---------------------------------- */
/* Pre-initialize */
pascal OSErr
FragmentInitialize(const CFragInitBlockPtr /*initInfo*/)
{
// -- Not needed if we don't use C++
// OSErr err = __initialize(initInfo);
// if (err != noErr)
// return err;
//
// g_my_connection_ID = (CFragConnectionID)initInfo->connectionID;
//
//
// SetDriverClosureMemory(initInfo->closureID, true);
return noErr;
}
pascal void
FragmentTerminate(void)
{
// -- Not needed if we don't use C++
// __terminate();
// DebugStr("¥pFrag term");
}
/* Initialize MacOS managers */
void
init_macos_toolbox(void)
{
#if !BOOTX_BUILD_INIT
OSErr err;
ProcessInfoRec infos;
ProcessSerialNumber me;
Str255 my_name;
#endif
InitGraf(&qd.thePort);
InitFonts();
InitWindows();
#if BOOTX_BUILD_INIT
InitMenus();
#endif
TEInit();
InitDialogs(nil);
#if BOOTX_BUILD_INIT
InitAllPacks();
#endif
InitCursor();
#if BOOTX_BUILD_INIT
LMSetDeskHook(NULL);
LMSetDragHook(NULL);
LMSetGhostWindow(NULL);
TextFont(0);
TextSize(12);
DrawMenuBar();
#endif
#if BOOTX_BUILD_INIT
MoreMasters();
#else
MaxApplZone();
MoreMasters();
MoreMasters();
MoreMasters();
MoreMasters();
FlushEvents(everyEvent, 0);
err = GetCurrentProcess(&me);
if (err != noErr) {
DEBUG_ERR(err, error_get_current_process);
ExitToShell();
}
memset(&infos, 0, sizeof(ProcessInfoRec));
infos.processInfoLength = sizeof(ProcessInfoRec);
infos.processName = my_name;
infos.processAppSpec = &g_application_spec;
err = GetProcessInformation(&me, &infos);
if (err != noErr)
{
DEBUG_ERR(err, error_get_process_infos);
ExitToShell();
}
#endif
}
/* Create the dialog, setup initial values, and gather infos about some
* of the items for later use.
*/
Boolean
create_dialog()
{
DialogPeek dp;
short itemType;
Rect itemBox;
Handle itemHandle;
FontInfo theFontInfo;
g_dialog = GetNewDialog(dialog_main, NULL, (WindowPtr)-1);
if (!g_dialog)
{
DEBUG_ERR(0, error_create_dialog);
return false;
}
SetPort(g_dialog);
dp = (DialogPeek)g_dialog;
TextFont((**(dp->textH)).txFont = 3);
TextSize((**(dp->textH)).txSize = 9);
TextFace((**(dp->textH)).txFace = 0);
GetFontInfo(&theFontInfo);
(**(dp->textH)).lineHeight = theFontInfo.ascent + theFontInfo.descent + theFontInfo.leading;
(**(dp->textH)).fontAscent = theFontInfo.ascent;
GetDialogItem(g_dialog, text_status_display, &itemType, &g_status_item, &itemBox) ;
GetDialogItem(g_dialog, button_boot_linux, &itemType, &itemHandle, &itemBox) ;
if (!g_boot_choices[boot_linux][1])
HiliteControl((ControlHandle)itemHandle, 255);
GetDialogItem(g_dialog, button_boot_mklinux, &itemType, &itemHandle, &itemBox) ;
#if BOOTX_BUILD_INIT
if (!g_boot_choices[boot_mklinux][1])
HiliteControl((ControlHandle)itemHandle, 255);
#else
HideDialogItem(g_dialog, button_boot_mklinux);
#endif
GetDialogItem(g_dialog, check_use_ram_disk, &itemType, (Handle *)&g_use_ramdisk_cntl, &itemBox) ;
GetDialogItem(g_dialog, check_video_of_only, &itemType, (Handle *)&g_video_of_only_cntl, &itemBox) ;
GetDialogItem(g_dialog, check_set_l2cr, &itemType, (Handle *)&g_set_L2CR_cntl, &itemBox);
if (!g_L2CR_available)
HideDialogItem(g_dialog, check_set_l2cr);
SetDialogTracksCursor(g_dialog, true);
SetControlValue(g_use_ramdisk_cntl, g_use_ramdisk);
RGBBackColor(&g_back_color);
GetDialogItem(g_dialog, menu_kernels, &itemType, (Handle *)&g_kernel_menu, &itemBox);
return true;
}
void
get_options_from_dialog(void)
{
short itemType;
Rect itemBox;
Handle itemHandle;
Str255 tempStr;
int i;
tempStr[0] = 0;
g_kernel_args[0] = 0;
if (!g_use_ramdisk)
{
GetDialogItem(g_dialog, field_root_device, &itemType, &itemHandle, &itemBox);
if (itemHandle)
GetDialogItemText(itemHandle, tempStr);
if (tempStr[0])
{
pstrcpy(g_kernel_args, "¥proot=/dev/");
pstrcat(g_kernel_args, tempStr);
}
}
tempStr[0] = 0;
GetDialogItem(g_dialog, field_kernel_args, &itemType, &itemHandle, &itemBox);
if (itemHandle)
GetDialogItemText(itemHandle, tempStr);
if (tempStr[0])
{
if (g_kernel_args[0])
pstrcat(g_kernel_args, "¥p ");
pstrcat(g_kernel_args, tempStr);
}
// Eventually update kernel args for ofonly mode
if (g_video_of_only)
{
if (g_kernel_args[0])
pstrcat(g_kernel_args, "¥p ");
pstrcat(g_kernel_args, "¥pvideo=ofonly");
}
// Get selected kernel
g_kernel_items_choice = 0;
for (i=0; i<g_kernel_items_count; i++)
if (g_kernel_items[i].menu_item == GetControlValue(g_kernel_menu))
g_kernel_items_choice = i;
}
/* I'll let you guess what this function does ;-)
*/
void
dispose_dialog()
{
Boolean hasEvent;
/* Flush any pending update event */
do {
EventRecord event;
hasEvent = WaitNextEvent(everyEvent & (~diskMask), &event, 1, NULL);
if (hasEvent && (event.what == updateEvt)) {
SetPort((WindowPtr)event.message);
BeginUpdate((WindowPtr)event.message);
EndUpdate((WindowPtr)event.message);
}
} while(hasEvent);
/* Get rid of the dialog */
DisposeDialog(g_dialog);
g_dialog = NULL;
}
void
setup_default_buttons(void)
{
Rect r_erase, r_fill;
RgnHandle erase_rgn, rgn1, rgn2;
PenState state;
short button, i;
short itemType;
Handle itemHandle;
SetPort(g_dialog);
button = g_boot_choices[g_current_choice][0];
SetDialogDefaultItem(g_dialog, button);
SetDialogCancelItem(g_dialog, button_boot_macos);
erase_rgn = NewRgn();
rgn1 = NewRgn();
rgn2 = NewRgn();
for (i=0; i<boot_choice_count; i++)
if (i == g_current_choice)
GetDialogItem(g_dialog, g_boot_choices[i][0], &itemType, &itemHandle, &r_fill) ;
else
{
GetDialogItem(g_dialog, g_boot_choices[i][0], &itemType, &itemHandle, &r_erase);
RectRgn(rgn1, &r_erase);
InsetRect(&r_erase, -4, -4);
RectRgn(rgn2, &r_erase);
DiffRgn(rgn2, rgn1, rgn1);
UnionRgn(rgn1, erase_rgn, erase_rgn);
}
/* We still do the erasing & drawing of the default outline
since some versions of the default filter proc will not handle
correctly the dynamic changing. Appearance Manager patches
FrameRoundRect so this won't harm. Under MacOS 8.1, the Appearance
won't be available so early during boot. Under 8.5, things seems to be
different and you'll get the AM look at startup.
*/
GetPenState(&state);
PenNormal();
PenSize(3,3);
InsetRect(&r_fill, -4, -4);
EraseRgn(erase_rgn);
FrameRoundRect(&r_fill, 16, 16);
SetPenState(&state);
DisposeRgn(rgn1);
DisposeRgn(rgn2);
DisposeRgn(erase_rgn);
}
#if BOOTX_BUILD_INIT
/* This function allocates memory by moving down the BufPtr low memory globals. This
* is a special technique for use _only_ by system extensions that need a large amount
* that won't be available in the system heap. That's our case. The strange formula
* we use with MemTop comes from the MacOS historical roots, the system will make sure
* that MemTop has a correct value for this formula to apply.
* Note that this memory will be pageable.
*/
Ptr
alloc_high_mem(unsigned long count)
{
Ptr limit = (Ptr)((UInt32)LMGetMemTop()/2 + 1024);
Ptr bufPtr = LMGetBufPtr();
count += 256;
if ((bufPtr - limit) < count)
return NULL;
LMSetBufPtr(bufPtr - count);
bufPtr -= count;
return (Ptr)(((UInt32)bufPtr | 0xFFUL) + 1);
}
#endif
OSErr
locate_file(short namesResourceID, OSType defaultFolder, FSSpecPtr outSpec)
{
int i;
OSErr err;
short defaultVRefNum;
long defaultParID;
static Str255 fileName;
#if !BOOTX_BUILD_INIT
Boolean tryApp;
#endif
// Build kernel FSSpec
err = FindFolder( kOnSystemDisk,
defaultFolder,
false,
&defaultVRefNum,
&defaultParID);
if (err != noErr)
return err;
i=1;
#if !BOOTX_BUILD_INIT
tryApp = true;
#endif
do
{
GetIndString(fileName, namesResourceID, i);
if (fileName[0] == 0)
{
#if !BOOTX_BUILD_INIT
if (tryApp)
{
tryApp = false;
i = 1;
continue;
}
#endif
return fnfErr;
}
#if BOOTX_BUILD_INIT
err = FSMakeFSSpec( defaultVRefNum, defaultParID, fileName, outSpec);
#else
err = FSMakeFSSpec( tryApp ? g_application_spec.vRefNum : defaultVRefNum,
tryApp ? g_application_spec.parID : defaultParID,
fileName,
outSpec);
#endif
if (err == noErr)
{
Boolean wasFolder;
Boolean wasAlias;
/* Resolve it in case it was an alias - should do it silently however !*/
ResolveAliasFile( outSpec,
true,
&wasFolder,
&wasAlias);
break;
}
i++;
} while(true);
return err;
}
/* Locate the kernel and the ram disk (optional) files on disk.
* This function uses a looks for them first next to the BootX application,
* then in the system folder's root.
* For each file, all possible names are tested. The names are stored inside
* BootX resources STR#, ID 128 for kernel names, ID 129 for ramdisk names
*/
Boolean
locate_ramdisk(void)
{
OSErr err;
// Lookup ram disk
g_have_ramdisk = false;
err = locate_file(string_ramdisk_names, kSystemFolderType, &g_ramdisk_spec);
if (err != noErr)
err = locate_file(string_ramdisk_names, kExtensionFolderType, &g_ramdisk_spec);
if (err == noErr)
g_have_ramdisk = true;
return true;
}
#if BOOTX_BUILD_INIT
/* Save bad mount events in our special queue. We repost them later so they can
* eventually be handled by an external file system that gets loaded after
* us (like MountX).
*/
void
save_mount_event(EventRecord *event)
{
saved_mount_t* stub;
static s_save_count = 0;
#if BOOTX_TRACE
ST_Printf(0,0,"saving mount event, msg: 0x%x, error: 0x%x¥n",
(int)LoWord(event->message), HiWord(event->message));
#endif
if ((++s_save_count) > 32)
{
DEBUG_ERR(-666, error_too_many_mounts);
return;
}
stub = (saved_mount_t*)NewPtr(sizeof(saved_mount_t));
if (stub == NULL)
{
DEBUG_ERR(MemError(), error_alloc_event_stub);
return;
}
stub->message = event->message;
Enqueue((QElemPtr)stub, &g_mount_queue);
}
/* Repost events gathered previously */
void
resend_mount_events(void)
{
saved_mount_t* stub;
Handle h;
Boolean disable;
Boolean only_err;
h = GetResource('NOMT', 666);
disable = (h && (*h) && (**h));
only_err = (disable && ((**h) == 2));
if (h)
ReleaseResource(h);
while(NULL != (stub = (saved_mount_t *)g_mount_queue.qHead))
{
if (Dequeue((QElemPtr)stub, &g_mount_queue) == noErr)
{
OSErr eventResult = HiWord(stub->message);
short driveNumber = LoWord(stub->message);
if (!disable ||
(only_err && ((eventResult == noErr) || (HiWord(stub->message) == volOnLinErr))))
{
#if BOOTX_TRACE
ST_Printf(0,0,"posting event, drive: 0x%x, error was: 0x%x¥n", (int)driveNumber, eventResult);
#endif
PostEvent(diskEvt, driveNumber);
}
DisposePtr((Ptr)stub);
}
}
}
#endif
/* This function looks up possible linux kernel files and fills the
kernel menu */
void
lookup_kernels(void)
{
FSSpec spec, folder_spec, previous;
Str255 folder_name;
Boolean isDir, has_previous;
long folder_id, defaultParID;
short defaultVRefNum;
OSErr err;
// Lookup kernel old way in system folder/application
has_previous = false;
err = locate_file(string_kernel_names, kSystemFolderType, &spec);
if (err == noErr) {
memset(&g_kernel_items[g_kernel_items_count], 0, sizeof(kernel_item_t));
g_kernel_items[g_kernel_items_count].file = spec;
err = check_kernel(&g_kernel_items[g_kernel_items_count], false);
if (err == noErr) {
g_kernel_items_count++;
has_previous = true;
previous = spec;
}
}
// Lookup kernel old way in extensions folder/application
err = locate_file(string_kernel_names, kExtensionFolderType, &spec);
if (err == noErr) {
if (!(has_previous && (spec.vRefNum == previous.vRefNum)
&& (spec.parID == previous.parID)
&& EqualString(spec.name, previous.name, false, false))) {
memset(&g_kernel_items[g_kernel_items_count], 0, sizeof(kernel_item_t));
g_kernel_items[g_kernel_items_count].file = spec;
err = check_kernel(&g_kernel_items[g_kernel_items_count], false);
if (err == noErr)
g_kernel_items_count++;
}
}
GetIndString(folder_name, string_kernel_folder, 1);
// Now check for a "Linux Kernels" folder next to BootX (app only)
#if !BOOTX_BUILD_INIT
err = FSMakeFSSpec( g_application_spec.vRefNum,
g_application_spec.parID,
folder_name, &folder_spec);
if (err == noErr) {
Boolean wasFolder;
Boolean wasAlias;
/* Resolve it in case it was an alias - should do it silently however !*/
ResolveAliasFile(&folder_spec, true, &wasFolder, &wasAlias);
err = FSpGetDirectoryID(&folder_spec, &folder_id, &isDir);
if ((err == noErr) && isDir) {
err = FSpIterateDirectory( &folder_spec,
1,
kernel_iterate_filter_proc,
NULL);
}
}
#endif
// Now check for a "Linux Kernels" folder in the system folder
// Build kernel FSSpec
err = FindFolder( kOnSystemDisk,
kSystemFolderType,
false,
&defaultVRefNum,
&defaultParID);
if (err == noErr) {
err = FSMakeFSSpec( defaultVRefNum,
defaultParID,
folder_name, &folder_spec);
if (err == noErr) {
Boolean wasFolder;
Boolean wasAlias;
/* Resolve it in case it was an alias - should do it silently however !*/
ResolveAliasFile(&folder_spec, true, &wasFolder, &wasAlias);
err = FSpGetDirectoryID(&folder_spec, &folder_id, &isDir);
if ((err == noErr) && isDir) {
err = FSpIterateDirectory( &folder_spec,
1,
kernel_iterate_filter_proc,
NULL);
}
}
}
}
pascal void
kernel_iterate_filter_proc( const CInfoPBRec* const cpbPtr,
Boolean *quitFlag,
void* yourDataPtr)
{
#pragma unused (quitFlag,yourDataPtr)
kernel_item_t* kern_infos = &g_kernel_items[g_kernel_items_count];
memset(kern_infos, 0, sizeof(kernel_item_t));
pstrcpy(kern_infos->file.name, cpbPtr->hFileInfo.ioNamePtr);
kern_infos->file.parID = cpbPtr->hFileInfo.ioFlParID;
kern_infos->file.vRefNum = cpbPtr->hFileInfo.ioVRefNum;
if (check_kernel(kern_infos, false) == noErr) {
g_kernel_items_count++;
}
}
void
build_kernels_menu(void)
{
int item, i;
short lastVol;
long lastDirID;
MenuHandle menu;
PopupPrivateDataHandle dataH;
lastDirID = 0;
lastVol = 0;
item = 1;
dataH = (PopupPrivateDataHandle) (**g_kernel_menu).contrlData;
menu = NULL;
if (dataH != NULL)
menu = (**dataH).mHandle;
if (!menu)
return;
while(CountMenuItems(menu))
DeleteMenuItem(menu, 1);
for (i=0; i<g_kernel_items_count; i++) {
if ((item > 1) && ((g_kernel_items[i].file.vRefNum != lastVol)
|| (g_kernel_items[i].file.parID != lastDirID))) {
AppendMenu(menu, "¥p(-");
item++;
}
AppendMenu(menu, "¥p ");
SetMenuItemText(menu, item, g_kernel_items[i].file.name);
g_kernel_items[i].menu_item = item;
item++;
lastDirID = g_kernel_items[i].file.parID;
lastVol = g_kernel_items[i].file.vRefNum;
}
SetControlMinimum(g_kernel_menu, 1);
SetControlMaximum(g_kernel_menu, item);
SetControlValue(g_kernel_menu, 1);
}
/* Entry point */
pascal void
main(void)
{
Boolean finished;
Boolean counter_on;
Boolean stop_counter;
Boolean simulate;
GrafPtr oldPort;
ModalFilterUPP std_filter;
UInt32 last_disp_ticks;
static Str255 tempStr;
long response;
/* Silently dies on sheepshaver */
if (((*(UInt32 *)0x2800)) == 'Baah') {
#if BOOTX_BUILD_INIT
FragmentTerminate();
#endif
return;
}
g_my_zone = GetZone();
#if BOOTX_TRACE
#if BOOTX_BUILD_INIT
ST_TraceInit("BootX INIT", 1, NULL);
#else
ST_TraceInit("BootX App", 1, NULL);
#endif
#endif
init_macos_toolbox();
g_dialog = NULL;
g_mount_queue.qHead = NULL;
g_mount_queue.qTail = NULL;
g_mount_queue.qFlags = NULL;
g_ramdisk = NULL;
g_L2CR_pref = false;
g_L2CR_set = false;
g_L2CR_value = 0;
g_L2CR_available = false;
g_entry_ticks = TickCount();
g_vm_present = false;
if (Gestalt(gestaltVMAttr, &response) == noErr)
if (response & (1 << gestaltVMPresent))
g_vm_present = true;
if (Gestalt(gestaltNativeCPUfamily, &response) == noErr)
{
if (response == gestaltCPU750)
g_L2CR_available = true;
} else if (Gestalt(gestaltNativeCPUtype, &response) == noErr)
if (response == gestaltCPU750)
g_L2CR_available = true;
// g_L2CR_available = true;
g_arch_PCI = false;
if (Gestalt(gestaltOpenFirmwareInfo, &response) == noErr)
if (Gestalt(gestaltNameRegistryVersion, &response) == noErr)
g_arch_PCI = true;
if (((long)RegistryEntryIDInit == kUnresolvedCFragSymbolAddress)||
((long)FlushProcessorCache == kUnresolvedCFragSymbolAddress))
g_arch_PCI = false;
g_page_size = g_arch_PCI ? GetLogicalPageSize() : 4096;
GetWMgrPort(&oldPort);
SetPort(oldPort);
// Setup default BootX options
GetIndString(g_kernel_args, string_kernel_args, 1);
GetIndString(tempStr, string_boot_delay, 1);
StringToNum(tempStr, (long *)&g_autoboot_delay);
// if (g_autoboot_delay > 30)
// g_autoboot_delay = 30;
g_autoboot_delay *= 60;
g_current_choice = boot_macos;
g_video_of_only = false;
// Setup device tree options
device_tree_skip_macos = 1; // Skip MacOS drivers
device_tree_max_prop_length = 1024; // Max copied property length
// Locate the kernel and ramdisk files
lookup_kernels();
g_boot_choices[boot_linux][1] = (g_kernel_items_count != 0);
if (g_kernel_items_count)
locate_ramdisk();
g_use_ramdisk = g_have_ramdisk;
#if BOOTX_BUILD_INIT
// Locate MkLinux booter
g_boot_choices[boot_mklinux][1] = locate_mklinux();
#endif
#if BOOTX_TRACE
ST_Printf(0,0,"VM present : %d¥n", g_vm_present);
ST_Printf(0,0,"Page size : %d¥n", g_page_size);
ST_Printf(0,0,"Autoboot_delay : %d¥n", g_autoboot_delay);
ST_Printf(0,0,"L2CR available on this CPU : %d¥n", g_L2CR_available);
if (g_have_ramdisk)
ST_Printf(0,0,"RAM-disk found¥n");
if (g_boot_choices[boot_linux][1])
ST_Printf(0,0,"Linux kernel found¥n");
if (g_boot_choices[boot_mklinux][1])
ST_Printf(0,0,"MkLinux booter found¥n");
#endif
if (!g_boot_choices[boot_linux][1] && !g_boot_choices[boot_mklinux][1])
{
DEBUG_ERR(0, error_no_kernel);
goto bail;
}
// Create main dialog box
if (!create_dialog())
goto bail;
if (g_kernel_items_count)
build_kernels_menu();
// Load eventual prefs file
load_prefs();
// Display the dialog
SelectDialogItemText(g_dialog, field_kernel_args, 0, 255);
ShowWindow(g_dialog);
DrawDialog(g_dialog);
// Main event loop
finished = false;
simulate = false;
stop_counter = false;
#if BOOTX_BUILD_INIT
counter_on = true;
#else
counter_on = false;
#endif
last_disp_ticks = g_entry_ticks - 60;
if (GetStdFilterProc(&std_filter) != noErr)
{
std_filter = NULL;
DEBUG_ERR(0,error_no_std_filter);
}
while(!finished)
{
EventRecord event;
short itemHit;
DialogPtr dialog;
Boolean handled;
Boolean hasEvent;
SetPort(g_dialog);
hasEvent = WaitNextEvent(everyEvent, &event, 1, NULL);
SetPort(g_dialog);
SetZone(g_my_zone);
itemHit = 0;
dialog = g_dialog;
handled = false;
if (counter_on)
{
UInt32 now = TickCount();
if ((now - g_entry_ticks) >= g_autoboot_delay)
{
counter_on = false;
itemHit = g_boot_choices[g_current_choice][0];
simulate = true;
handled = true;
}
else if ((now - last_disp_ticks) >= 30)
{
static char temp[256];
sprintf(temp, "Boot in %d seconds ", (int)((g_autoboot_delay - (now - g_entry_ticks)) / 60));
c2pstr(temp);
SetDialogItemText(g_status_item, (StringPtr)temp);
last_disp_ticks = now;
}
}
if (!handled)
handled = ((std_filter != NULL)
? CallModalFilterProc(std_filter, g_dialog, &event, &itemHit)
: false);
if (!handled && hasEvent)
{
UInt8 c;
switch(event.what)
{
case updateEvt:
if ((DialogPtr)event.message == g_dialog)
{
handled = TRUE;
BeginUpdate(g_dialog);
RGBBackColor(&g_back_color);
DrawDialog(g_dialog);
setup_default_buttons();
EndUpdate(g_dialog);
} else
{
BeginUpdate((WindowPtr)event.message);
EndUpdate((WindowPtr)event.message);
}
break;
case keyDown:
case autoKey:
c = (event.message & charCodeMask);
if (event.modifiers & cmdKey)
{
switch(c)
{
case 'q':
case 'Q':
itemHit = button_boot_macos;
handled = true;
break;
case 's':
case 'S':
itemHit = button_set_default;
handled = true;
simulate = true;
break;
}
} else
{
switch(c)
{
case 0x09: // Tab
do
g_current_choice = (g_current_choice + 1) % boot_choice_count;
while(!g_boot_choices[g_current_choice][1]);
setup_default_buttons();
handled = true;
break;
/* This is done for us by the standard filter
case 0x0D: // Return
case 0x03: // Enter
simulate = true;
handled = true;
itemHit = g_boot_choices[g_current_choice][0];
break;
case 0x1B:
simulate = true;
handled = true;
itemHit = button_boot_macos;
break;
*/
}
}
// We stop the counter when a key is pressed
stop_counter = true;
break;
case diskEvt:
#if BOOTX_BUILD_INIT
save_mount_event(&event);
#else
if ((HiWord(event.message) != noErr)&&(HiWord(event.message) != volOnLinErr))
{
Point pt = {100, 100};
DIBadMount(pt, event.message);
}
#endif
break;
}
}
// All non-filtered events are given to the default event proc.
if (!handled && IsDialogEvent(&event))
handled = DialogSelect(&event, &dialog, &itemHit);
if (handled)
{
if (dialog == g_dialog)
{
int i;
if (simulate)
{
Rect itemBox;
short itemType;
Handle itemHandle;
UInt32 toto;
GetDialogItem (g_dialog, itemHit, &itemType, &itemHandle, &itemBox);
HiliteControl((ControlHandle)itemHandle, 1);
Delay(10, &toto);
HiliteControl((ControlHandle)itemHandle, 0);
simulate = false;
}
for(i=0; i<boot_choice_count; i++)
if (g_boot_choices[i][0] == itemHit)
{
g_current_choice = i;
finished = true;
break;
}
switch(itemHit)
{
case button_set_default:
stop_counter = true;
save_prefs();
break;
case check_use_ram_disk:
stop_counter = true;
if (g_have_ramdisk)
{
g_use_ramdisk = !g_use_ramdisk;
SetControlValue(g_use_ramdisk_cntl, g_use_ramdisk);
}
break;
case check_video_of_only:
stop_counter = true;
g_video_of_only = !g_video_of_only;
SetControlValue(g_video_of_only_cntl, g_video_of_only);
break;
case check_set_l2cr:
stop_counter = true;
if (g_L2CR_available && g_L2CR_pref)
{
g_L2CR_set = !g_L2CR_set;
SetControlValue(g_set_L2CR_cntl, g_L2CR_set);
}
break;
case menu_kernels:
stop_counter = true;
break;
default:
break;
}
}
}
if (counter_on && stop_counter)
{
counter_on = FALSE;
SetDialogItemText(g_status_item, "¥p");
}
}
switch (g_current_choice)
{
case boot_linux:
get_options_from_dialog();
dispose_dialog();
#if !BOOTX_BUILD_INIT
SetZone(SystemZone());
#endif
prepare_and_boot(&g_kernel_items[g_kernel_items_choice]);
SetZone(g_my_zone);
break;
case boot_mklinux:
SetZone(g_my_zone);
dispose_dialog();
do_boot_mklinux();
break;
}
bail:
SetZone(g_my_zone);
if (g_dialog)
dispose_dialog();
GetWMgrPort(&oldPort);
SetPort(oldPort);
#if BOOTX_BUILD_INIT
SetZone(SystemZone());
resend_mount_events();
SetZone(g_my_zone);
#endif
#if BOOTX_TRACE
ST_TraceDispose();
#endif
#if BOOTX_BUILD_INIT
FragmentTerminate();
#endif
}
void
check_burgundy_patch(void)
{
THz oldZone;
Handle patchRsrc;
oldZone = GetZone();
SetZone(SystemZone());
patchRsrc = Get1Resource('GLUE', 130);
if (patchRsrc == NULL) {
goto bail;
}
DetachResource(patchRsrc);
HLock(patchRsrc);
if (!CallUniversalProc((RoutineDescriptor *)*patchRsrc,
kCStackBased | RESULT_SIZE(SIZE_CODE(sizeof(Boolean))))) {
HUnlock(patchRsrc);
DisposeHandle(patchRsrc);
}
bail:
SetZone(oldZone);
}
/* The main boot operations are here: making of the boot-infos, loading of the
* kernel, etc...
*
* !!! This function should really be broken in pieces for readability and
* maintainability !!!
*/
void
prepare_and_boot(kernel_item_t* kern_infos)
{
PPCRegisterList regList;
Handle boot_resource;
Handle boot_resource_PPC;
Ptr devTree;
UInt32 kern_size;
UInt32 devTreeSize;
UInt32 dispRegOff;
UInt32 allocSpace;
void* strap_entry;
UInt32 strap_phys_entry, strap_dest;
UInt32* map;
UInt32* map_loc;
UInt32 map_size, boot_map_addr, strap_size, prec, i, j, k, temp_page;
UInt32 setupVideo = false;
void* boot_glue_68k;
void* boot_glue_PPC;
OSErr err;
#if BOOTX_BUILD_INIT
Ptr saveBufPtr = LMGetBufPtr();
#endif
g_stuff = (UInt8 *)g_stuff_ptr = NULL;
#if !BOOTX_BUILD_INIT
SetCursor(*GetCursor(watchCursor));
#endif
if (g_arch_PCI) {
err = build_pci_device_tree(&devTree, &devTreeSize, &dispRegOff);
if (err != noErr)
return;
} else
{
devTree = NULL;
devTreeSize = 0;
dispRegOff = 0;
}
if (check_kernel(kern_infos, true))
goto out_freedevtree;
if (g_use_ramdisk && (open_ramdisk(&g_ramdisk_spec) != noErr))
goto out_close_kernel;
/* First we calculate the sizes and offsets of the different
elements to store with the kernel */
if (!g_use_ramdisk)
g_ramdisk_size = 0;
kern_size = (kern_infos->file_size > kern_infos->mem_size) ?
kern_infos->file_size : kern_infos->mem_size;
g_stuff_offsets[offset_kernel] = 0;
g_stuff_offsets[offset_stack] = prec = PAGE_ALIGN(kern_size);
g_stuff_offsets[offset_bootinfo] = prec = PAGE_ALIGN(prec + BOOT_KERNEL_STACK_SIZE);
g_stuff_offsets[offset_arguments] = prec = LINE_ALIGN(prec + sizeof(boot_infos_t));
g_stuff_offsets[offset_color_map] = prec = LINE_ALIGN(prec + g_kernel_args[0] + 1);
g_stuff_offsets[offset_device_tree] = prec = LINE_ALIGN(prec + BOOTX_COLORTABLE_SIZE);
g_stuff_offsets[offset_ramdisk] = prec = PAGE_ALIGN(prec + devTreeSize);
g_stuff_offsets[offset_unmangler] = prec = PAGE_ALIGN(prec + g_ramdisk_size);
allocSpace = prec + g_page_size;
#if !BOOTX_BUILD_INIT
SetZone(SystemZone());
#endif
#if BOOTX_LOG_MAP
open_log_file();
log_printf("Original offsets:¥n");
log_printf("g_stuff_offsets[offset_kernel] = 0x%08lx¥n", g_stuff_offsets[offset_kernel]);
log_printf("g_stuff_offsets[offset_stack] = 0x%08lx¥n", g_stuff_offsets[offset_stack]);
log_printf("g_stuff_offsets[offset_bootinfo] = 0x%08lx¥n", g_stuff_offsets[offset_bootinfo]);
log_printf("g_stuff_offsets[offset_arguments] = 0x%08lx¥n", g_stuff_offsets[offset_arguments]);
log_printf("g_stuff_offsets[offset_color_map] = 0x%08lx¥n", g_stuff_offsets[offset_color_map]);
log_printf("g_stuff_offsets[offset_device_tree] = 0x%08lx¥n", g_stuff_offsets[offset_device_tree]);
log_printf("g_stuff_offsets[offset_ramdisk] = 0x%08lx¥n", g_stuff_offsets[offset_ramdisk]);
log_printf("g_stuff_offsets[offset_unmangler] = 0x%08lx¥n", g_stuff_offsets[offset_unmangler]);
#endif
/* Allocate the big "stuffs" region where we store all those datas */
#if BOOTX_BUILD_INIT
g_stuff = (UInt8*)alloc_high_mem(allocSpace);
err = memFullErr;
#else
g_stuff = (UInt8*)NewPtrSysClear(allocSpace);
err = MemError();
#endif
if (!g_stuff) {
DEBUG_ERR(err, error_alloc_stuffs);
goto out_setzone;
}
err = noErr;
g_stuff_ptr = (Ptr)g_stuff;
g_stuff = (UInt8 *)PAGE_ALIGN(g_stuff);
memset(g_stuff + g_stuff_offsets[offset_stack], 0, BOOT_KERNEL_STACK_SIZE);
// -- Load kernel --
if (load_kernel(kern_infos, g_stuff + g_stuff_offsets[offset_kernel]))
goto out_setzone;
// --- Flush useless now
// if (g_arch_PCI)
// FlushProcessorCache(NULL, g_stuff + g_stuff_offsets[offset_kernel], g_kernel_memsize);
// else
// MakeDataExecutable(g_stuff + g_stuff_offsets[offset_kernel], g_kernel_memsize);
// -- Fill boot infos --
// Store version informations
g_boot_infos = (boot_infos_t *)(g_stuff + g_stuff_offsets[offset_bootinfo]);
memset(g_boot_infos, 0, sizeof(boot_infos_t));
g_boot_infos->version = BOOT_INFO_VERSION;
g_boot_infos->compatible_version = BOOT_INFO_COMPATIBLE_VERSION;
// Fill some fields of the boot_infos
err = Gestalt(gestaltMachineType, (long *)&g_boot_infos->machineID);
if (err != noErr)
g_boot_infos->machineID = 0;
g_boot_infos->architecture = 0;
// Setup arch flags and memory map for NuBus
if (g_arch_PCI) {
g_boot_infos->architecture |= BOOT_ARCH_PCI;
g_load_base = 0;
g_boot_infos->physMemoryMapSize = 0;
} else {
build_memory_map();
g_boot_infos->architecture |= BOOT_ARCH_NUBUS;
g_load_base = 0x200000;
switch(g_boot_infos->machineID) {
case gestaltPowerMac6100_60:
case gestaltPowerMac6100_66:
case 101: /* gestaltPowerMac6100_80 */
case gestaltPowerMac7100_66:
case gestaltPowerMac7100_80:
case 113: /* gestaltPowerMac7100_80_chipped */
case gestaltPowerMac8100_80:
case gestaltPowerMac8100_100:
case gestaltPowerMac8100_110:
case gestaltPowerMac8100_120:
case gestaltAWS9150_80:
case gestaltAWS9150_120:
g_boot_infos->architecture |= BOOT_ARCH_NUBUS_PDM;
break;
case gestaltPowerMac5200:
case gestaltPowerMac6200:
g_boot_infos->architecture |= BOOT_ARCH_NUBUS_PERFORMA;
break;
case gestaltPowerBook1400:
case gestaltPowerBook5300:
case gestaltPowerBookDuo2300:
g_boot_infos->architecture |= BOOT_ARCH_NUBUS_POWERBOOK;
break;
/* No default case, we let the kernel boot unsupported machines,
just in case... */
}
}
#if BOOTX_LOG_MAP
log_printf("Arch flags: 0x%lx, machineID: %d¥n",
g_boot_infos->architecture, g_boot_infos->machineID);
if (g_boot_infos->architecture & BOOT_ARCH_NUBUS) {
log_printf("phys memory map:¥n");
for (i=0;i<g_boot_infos->physMemoryMapSize; i++)
log_printf(" from 0x%08lx, 0x%08lx bytes¥n",
g_boot_infos->physMemoryMap[i].physAddr,
g_boot_infos->physMemoryMap[i].size);
}
#endif
// Total size of parameters after boot-infos
g_boot_infos->totalParamsSize = BI_OFFSET(offset_unmangler);
// Store the kernel params
g_boot_infos->kernelParamsOffset = BI_OFFSET(offset_arguments);
g_kernel_args[g_kernel_args[0]+1] = 0;
memcpy(g_stuff + g_stuff_offsets[offset_arguments], &g_kernel_args[1], g_kernel_args[0]+1);
// Make room for the colormap and store the offset. This offset will be used or cleared
// when the display device infos are really gathered by the low-level booter
g_boot_infos->dispDeviceColorsOffset = BI_OFFSET(offset_color_map);
// Copy in the device tree
g_boot_infos->deviceTreeOffset = BI_OFFSET(offset_device_tree);
g_boot_infos->deviceTreeSize = devTreeSize;
g_boot_infos->dispDeviceRegEntryOffset = dispRegOff;
memcpy(g_stuff + g_stuff_offsets[offset_device_tree], devTree, devTreeSize);
// -- Read in the ramdisk --
if (g_use_ramdisk) {
#if BOOTX_LOG_MAP
log_printf(0,0,"loading ramdisk...¥n");
#endif
if (load_ramdisk(g_stuff + g_stuff_offsets[offset_ramdisk]))
goto out_setzone;
g_boot_infos->ramDisk = BI_OFFSET(offset_ramdisk);
g_boot_infos->ramDiskSize = g_ramdisk_size;
}
// -- Build the copy-map that will be used by the boostrap to make --
// the kernel and all other allocated stuff contiguous
// First make all the stuff resident (but not necessarily contiguous)
err = make_resident(g_stuff, allocSpace, NO_BOOTSTRAP ? true : false);
if (err != noErr)
return;
#if !NO_BOOTSTRAP
// Make a map of pages used by the kernel stuffs
err = make_kernel_map(&map, &map_size);
if (err != noErr) {
DEBUG_ERR(err, error_map_kernel);
return;
}
#if BOOTX_LOG_MAP
log_printf("kernel map built, %d entries, loading bootsrap...¥n", map_size);
#endif
// the map size is multiplied by 2 to make room for "temp" copy
// operations that will be generated when source pages overlap
// destination. It's then multiplied by 12 which is the size of
// an entry in the copy-table.
strap_entry = load_bootstrap(map_size*24, &map_loc, &strap_size);
if (!strap_entry) {
DEBUG_ERR(err, error_load_bootstrap);
return;
}
// Make the boostrap resident and contiguous
err = make_resident(strap_entry, strap_size+g_page_size, true);
if (err != noErr)
return;
// The boostrap will move itself just after the kernel.
// We just make sure that source and dest don't overlap
// itself or one of the kernel pages
strap_size = PAGE_ALIGN(strap_size);
strap_dest = g_load_base + g_stuff_offsets[offset_unmangler];
strap_phys_entry = (UInt32)get_physical(strap_entry);
if ((strap_phys_entry < (strap_dest + strap_size)) &&
(strap_phys_entry > strap_dest - strap_size))
strap_dest = PAGE_ALIGN(strap_phys_entry + strap_size);
do
{
int overlap = false;
for (i=0; i<map_size; i++)
if ((map[i] >= strap_dest)&&(map[i] < (strap_dest+strap_size))) {
overlap = true;
strap_dest += g_page_size;
break;
}
if (!overlap)
break;
} while(true);
g_stuff_offsets[offset_unmangler] = strap_dest - g_load_base;
boot_map_addr = strap_dest + ((UInt32)map_loc - (UInt32)strap_entry);
temp_page = PAGE_ALIGN(strap_dest + strap_size);
#if BOOTX_LOG_MAP
log_printf("strap entry : 0x%lx¥n", strap_entry);
log_printf("strap dest : 0x%lx¥n", strap_dest);
log_printf("strap phys entry : 0x%lx¥n", strap_phys_entry);
log_printf("temp_page : 0x%lx¥n", temp_page);
log_printf("load_base : 0x%lx¥n", g_load_base);
#endif
// Now, we build the page-copy list for the bootstrap. For each
// kernel page, we first check if the destination already holds
// a kernel page. If this is the case, then this page is copied
// to a temp buffer, the original copy is done, and the temp
// buffer is set to the original source
#if BOOTX_LOG_MAP
log_printf("Copy map:¥n");
#endif
k = 0;
for(i=0; i<map_size; i++)
{
UInt32 src_page = map[i];
UInt32 dst_page = g_load_base + g_stuff_offsets[offset_kernel] + (g_page_size * i);
if (src_page == dst_page)
continue;
/* Check if the destination overlaps a yet uncopied page */
for (j=i+1; j<map_size; j++)
{
if (dst_page == map[j])
{
/* It overlaps. We add a "temp" copy of the dest page */
map_loc[k++] = dst_page;
map_loc[k++] = map[j] = get_temp_page(&temp_page, map+i, map_size-i);
map_loc[k++] = g_page_size;
#if BOOTX_LOG_MAP
log_printf("T 0x%08lx -> 0x%08lx¥n", map_loc[k-3], map_loc[k-2]);
#endif
break;
}
}
map_loc[k++] = src_page;
map_loc[k++] = dst_page;
map_loc[k++] = g_page_size;
#if BOOTX_LOG_MAP
log_printf(" 0x%08lx -> 0x%08lx¥n", map_loc[k-3], map_loc[k-2]);
#endif
}
map_loc[k++] = 0;
map_loc[k++] = 0;
map_loc[k++] = 0;
#if BOOTX_LOG_MAP
log_printf("list of %d copies for %d pages, %ld bytes¥n",
(k/3), map_size, g_stuff_offsets[offset_unmangler]);
#endif
DisposePtr((Ptr)map);
#endif // !NO_BOOTSTRAP
// -- Load the low-level 68k boot glue --
#if !BOOTX_BUILD_INIT
SetZone(SystemZone());
#endif
boot_resource = Get1Resource('GLUE', code_boot_glue68k);
if (!boot_resource)
{
err = ResError();
DEBUG_ERR(err, error_load_bootstrap68k);
goto out_setzone;
}
HNoPurge(boot_resource);
DetachResource(boot_resource);
HLock(boot_resource);
boot_glue_68k = *boot_resource;
// -- Load the low-level PPC boot glue --
boot_resource_PPC = Get1Resource('GLUE', code_boot_gluePPC);
if (!boot_resource_PPC)
{
err = ResError();
DEBUG_ERR(err, error_load_bootstrapPPC);
goto out_setzone;
}
HNoPurge(boot_resource_PPC);
DetachResource(boot_resource_PPC);
HLock(boot_resource_PPC);
boot_glue_PPC = *boot_resource_PPC;
// -- Setup PPC registers for supervisor mode --
#if NO_BOOTSTRAP
regList.PC = (UInt32)g_kernel_entry;
regList.GPR[1] = (UInt32)g_stuff + g_stuff_offsets[offset_stack] + BOOT_KERNEL_STACK_SIZE - 512;
regList.GPR[2] = 0;
regList.GPR[3] = 'BooX';
regList.GPR[4] = (UInt32)g_stuff + g_stuff_offsets[offset_bootinfo];
regList.GPR[5] = 0;
#else
regList.PC = (unsigned long)strap_entry;
regList.GPR[1] = g_load_base + g_stuff_offsets[offset_stack] + BOOT_KERNEL_STACK_SIZE - 512; // The stack for the kernel entry
regList.GPR[2] = 1; // r2 flag must be set to 1 by BootX
regList.GPR[3] = 'BooX'; // r3 contains 'BooX' ($426F6F58)
regList.GPR[4] = g_load_base + g_stuff_offsets[offset_bootinfo]; // r4 contains the boot infos ptr
regList.GPR[5] = NULL; /*iMacHack;*/ // r5 NULL, replaced by low-bootsrap with map base of fb
regList.GPR[6] = strap_phys_entry; // r6 contains phys addr. of bootstrap
regList.GPR[7] = strap_dest; // r7 contains dest addr. of bootstrap
regList.GPR[8] = strap_size;
regList.GPR[9] = boot_map_addr;
regList.GPR[10] = kern_infos->entry - (UInt32)g_stuff + g_load_base + g_stuff_offsets[offset_kernel];
regList.GPR[11] = 0;
#endif
#if BOOTX_LOG_MAP
log_printf("registers on entry:¥n");
log_printf("-------------------¥n");
log_printf(" PC: 0x%lx (logical)¥n", regList.PC);
log_printf(" r1: 0x%lx (SP)¥n", regList.GPR[1]);
log_printf(" r2: 0x%lx (should be 1)¥n", regList.GPR[2]);
log_printf(" r3: 0x%lx (BooX)¥n", regList.GPR[3]);
log_printf(" r4: 0x%lx (boot_infos)¥n", regList.GPR[4]);
log_printf(" r5: 0x%lx (fb map address)¥n", regList.GPR[5]);
log_printf(" r6: 0x%lx (strap_phys)¥n", regList.GPR[6]);
log_printf(" r7: 0x%lx (strap_dest)¥n", regList.GPR[7]);
log_printf(" r8: 0x%lx (strap_size)¥n", regList.GPR[8]);
log_printf(" r9: 0x%lx (boot_map_phys)¥n", regList.GPR[9]);
log_printf(" r10: 0x%lx (kernel entry)¥n", regList.GPR[10]);
log_printf(" r11: 0x%lx (do BAT mapping)¥n", regList.GPR[11]);
#endif
// -- Call the low-level PPC boot glue (returns a pointer to an UPP) --
// this call will make sure the code fragment is prepared and returns a pointer
// that can later be called by the 68k code
boot_glue_PPC = (void *)CallUniversalProc(boot_glue_PPC, kCStackBased | RESULT_SIZE(SIZE_CODE(sizeof(void*))));
// -- Call the low-level 68k boot glue (installs the shutdown proc) --
#if BOOTX_BUILD_INIT
setupVideo = g_video_of_only;
#endif
CallUniversalProc(boot_glue_68k, uppLowLevelBoot68kProcInfo, ®List, g_boot_infos, boot_glue_PPC, setupVideo);
// -- Reboot --
check_burgundy_patch();
#if BOOTX_LOG_MAP
log_printf("Sending MacOS shutdown...¥n");
close_log_file();
#endif
#if BOOTX_BUILD_INIT
ShutDwnStart();
DebugStr("¥pShould not get here !");
#else
send_restart_to_finder();
#endif
return;
out_disphandle:
DisposeHandle(boot_resource);
out_setzone:
#if BOOTX_LOG_MAP
close_log_file();
#endif
if (g_stuff_ptr)
DisposePtr((Ptr)g_stuff_ptr);
SetZone(g_my_zone);
if (g_use_ramdisk)
FSClose(g_ramdisk_ref);
out_close_kernel:
if (kern_infos->file_ref) {
FSClose(kern_infos->file_ref);
kern_infos->file_ref = 0;
}
out_freedevtree:
#if BOOTX_BUILD_INIT
LMSetBufPtr(saveBufPtr);
#else
DisposePtr(devTree);
#endif
}
static void
add_l2cr_property(UInt32 l2cr_value)
{
RegEntryIter iterator;
RegEntryIterationOp operation;
OSStatus err;
Boolean done, found;
char buffer[1024];
RegEntryID root_node_id;
RegEntryID entryID;
Boolean first;
// Create an Iterator
operation = kRegIterContinue;
err = RegistryEntryIterateCreate(&iterator);
if (err != noErr)
return;
err = RegistryEntryIDInit(&root_node_id);
if (err != noErr) {
RegistryEntryIterateDispose(&iterator);
return;
}
err = RegistryCStrEntryLookup(NULL, "Devices:device-tree", &root_node_id);
if (err != noErr) {
RegistryEntryIDDispose(&root_node_id);
RegistryEntryIterateDispose(&iterator);
return;
}
RegistryEntryIterateSet(&iterator, &root_node_id);
first = true;
found = false;
do {
RegPropertyValueSize size;
err = RegistryEntryIterate(&iterator, first ? kRegIterChildren : kRegIterContinue, &entryID, &done);
first = false;
if (!done && (err == noErr)) {
size = 1024;
err = RegistryPropertyGet(&entryID, "device_type", buffer, &size);
if (err == noErr) {
if ((strcmp(buffer, "cpus") == 0) || (strcmp(buffer, "cpu") == 0)) {
found = true;
RegistryPropertyCreate(&entryID, "l2cr-value", &l2cr_value, 4);
break;
}
}
}
} while (!done && !found && (err == noErr));
RegistryEntryIterateDispose(&iterator);
RegistryEntryIDDispose(&root_node_id);
}
OSErr
build_pci_device_tree(Ptr* outDevTree, UInt32 *outDevTreeSize, UInt32 *outDispRegOff)
{
Ptr devTree;
OSErr err;
// First make a copy of the device tree.
#if BOOTX_BUILD_INIT
Ptr saveBufPtr = LMGetBufPtr();
devTree = alloc_high_mem(NAME_REGISTRY_MAX_SIZE);
err = memFullErr;
#else
devTree = NewPtrSysClear(NAME_REGISTRY_MAX_SIZE);
err = MemError();
#endif
if (devTree == NULL) {
if (err == noErr) err = memFullErr;
DEBUG_ERR(err, error_alloc_device_tree);
return err;
}
err = noErr;
/* Add the "l2cr-value" property to the device-tree:cpu(s) node */
if (g_L2CR_available && g_L2CR_pref && g_L2CR_set)
add_l2cr_property(g_L2CR_value);
*outDevTreeSize = NAME_REGISTRY_MAX_SIZE;
err = copy_device_tree(devTree, outDevTreeSize, outDispRegOff);
if (err != noErr && (*outDevTreeSize > NAME_REGISTRY_MAX_SIZE)) {
DEBUG_ERR(memFullErr, error_device_tree_ovflw);
#if BOOTX_BUILD_INIT
LMSetBufPtr(saveBufPtr);
#else
DisposePtr(devTree);
#endif
return err;
} else if (err != noErr) {
DEBUG_ERR(err, error_copy_device_tree);
#if BOOTX_BUILD_INIT
LMSetBufPtr(saveBufPtr);
#else
DisposePtr(devTree);
#endif
}
*outDevTree = devTree;
return noErr;
}
void
build_memory_map(void)
{
Ptr base = *((Ptr *)MACOS_MEMMAP_PTR_ADDR);
int len = *((UInt16 *)MACOS_MEMMAP_SIZE_ADDR);
int i;
if (len <= MACOS_MEMMAP_BANK_0FFSET)
return;
base += MACOS_MEMMAP_BANK_0FFSET;
len -= MACOS_MEMMAP_BANK_0FFSET;
i = 0;
while(len >= 8) {
UInt32 addr = *((UInt32*)base);
UInt32 size = *((UInt32*)(base+4));
if (size) {
if ((i>0) && ((g_boot_infos->physMemoryMap[i-1].physAddr +
g_boot_infos->physMemoryMap[i-1].size) == addr)) {
g_boot_infos->physMemoryMap[i-1].size += size;
} else {
g_boot_infos->physMemoryMap[i].physAddr = addr;
g_boot_infos->physMemoryMap[i].size = size;
i++;
}
}
base += 8;
len -= 8;
}
g_boot_infos->physMemoryMapSize = i;
}
UInt32
get_temp_page(UInt32 *cur_temp, UInt32 *used_map, UInt32 used_size)
{
UInt32 page = *cur_temp;
UInt32 i;
again:
for (i=0; i<used_size; i++)
if (used_map[i] == page)
{
page += g_page_size;
goto again;
}
*cur_temp = page + g_page_size;
return page;
}
/* This function will build a simple map of the physical pages used
by the kernel stuffs
*/
OSErr
make_kernel_map(UInt32 **out_map, UInt32 *out_size)
{
LogicalToPhysicalTable table;
unsigned long count, i;
OSErr err;
UInt32 page_count;
UInt8* ptr;
page_count = g_stuff_offsets[offset_unmangler] / g_page_size;
ptr = g_stuff;
*out_map = (UInt32 *)NewPtrClear(page_count * sizeof(UInt32));
if (*out_map == NULL)
return memFullErr;
for (i=0; i<page_count; i++)
{
/* First get all physical/logical mappings */
table.logical.address = g_stuff + i*g_page_size;
table.logical.count = 1024;
count = sizeof( table ) / sizeof( MemoryBlock ) - 1;
err = GetPhysical( &table, &count );
if ( err != noErr)
return err;
(*out_map)[i] = (UInt32)table.physical[0].address;
}
*out_size = page_count;
return noErr;
}
/* Make a portion of memory resident. */
OSErr
make_resident(void* ptr, unsigned long size, Boolean contiguous)
{
OSErr err;
/*
if (!g_vm_present)
return noErr;
*/
if (size % g_page_size)
size = size + g_page_size - (size % g_page_size);
err = contiguous ? LockMemoryContiguous(ptr, size) : LockMemory(ptr, size);
bail:
if (err != noErr)
DEBUG_ERR(err, error_lock_memory);
return err;
}
/* Get the physical address, if possible, of a pointer. Note that
* we fail silently since we _do_ fail sometimes, like for screen
* base address. In this case, we just return the original pointer
*/
UInt8*
get_physical(void* ptr)
{
LogicalToPhysicalTable table;
unsigned long count;
OSErr err;
table.logical.address = ptr;
table.logical.count = 1024;
count = sizeof( table ) / sizeof( MemoryBlock ) - 1;
err = GetPhysical( &table, &count );
if ( err != noErr)
return ptr;
return (UInt8 *)(table.physical[0].address);
}
/* Open the kernel image and find out what sort of image it is.
* For ELF kernels we find out the offset, size on disk and
* size in memory of the kernel image.
*/
#define MAX_PHDRS 10
OSErr
check_kernel(kernel_item_t* kern_infos, Boolean will_load)
{
OSErr err;
long nb;
int i;
Elf32_Ehdr e;
Elf32_Phdr p[MAX_PHDRS];
UInt32 total_file_size;
Boolean wasFolder;
Boolean wasAlias;
/* Resolve it in case it was an alias - should do it silently however !*/
ResolveAliasFile(&kern_infos->file, true, &wasFolder, &wasAlias);
err = FSpOpenDF(&kern_infos->file, fsRdPerm, &kern_infos->file_ref);
if (err != noErr) {
if (will_load)
DEBUG_ERR(err, error_open_kernel);
return err;
}
err = GetEOF(kern_infos->file_ref, &nb);
if (err != noErr) {
if (will_load)
DEBUG_ERR(err, error_get_kernel_size);
goto out;
}
total_file_size = nb;
nb = sizeof(e);
err = FSRead(kern_infos->file_ref, &nb, &e);
if (err != noErr) {
if (will_load)
DEBUG_ERR(err, error_read_kernel_header);
goto out;
}
/* Check if it is an executable elf binary. */
err = -1;
if (!(e.e_ident[EI_MAG0] == ELFMAG0 && e.e_ident[EI_MAG1] == ELFMAG1 &&
e.e_ident[EI_MAG2] == ELFMAG2 && e.e_ident[EI_MAG3] == ELFMAG3)) {
if (will_load)
DEBUG_ERR(0, error_kernel_not_elf);
goto out;
}
if (e.e_ident[EI_CLASS] != ELFCLASS32
|| e.e_ident[EI_DATA] != ELFDATA2MSB) {
if (will_load)
DEBUG_ERR(0, error_kernel_not_PPC32MSB);
goto out;
}
if (!will_load) {
FSClose(kern_infos->file_ref);
kern_infos->file_ref = 0;
return noErr;
}
/* Read in the program header */
if (e.e_phnum > MAX_PHDRS)
e.e_phnum = MAX_PHDRS;
nb = e.e_phnum * sizeof(Elf32_Phdr);
if ((err = SetFPos(kern_infos->file_ref, fsFromStart, (long) e.e_phoff)) != noErr
|| (err = FSRead(kern_infos->file_ref, &nb, (Ptr) p)) != noErr) {
DEBUG_ERR(err, error_read_kernel_header2);
goto out;
}
kern_infos->file_size = 0;
kern_infos->offset = 0;
kern_infos->mem_size = 0;
kern_infos->entry = 0;
#define ADDRMASK 0x0fffffff
/* Scan through the program header */
for (i = 0; i < e.e_phnum; ++i) {
unsigned int off = 0;
if (p[i].p_type != PT_LOAD || p[i].p_offset == 0)
continue;
if (kern_infos->file_size == 0) {
kern_infos->offset = p[i].p_offset;
kern_infos->entry = ((e.e_entry & ADDRMASK) - (p[i].p_vaddr & ADDRMASK));
} else if (p[i].p_offset > kern_infos->offset) {
off = p[i].p_offset - kern_infos->offset;
} else
continue;
kern_infos->file_size = p[i].p_filesz + off;
kern_infos->mem_size = p[i].p_memsz + off;
}
err = -1;
if (kern_infos->file_size == 0) {
DEBUG_ERR(0, error_no_loadable_seg);
goto out;
}
if (kern_infos->file_size + kern_infos->offset > total_file_size)
kern_infos->file_size = total_file_size - kern_infos->offset;
return 0;
out:
if (kern_infos->file_ref) {
FSClose(kern_infos->file_ref);
kern_infos->file_ref = 0;
}
return err;
}
void *
load_bootstrap(long mapSize, UInt32** outMapBegin,UInt32 *outTotalSize)
{
THz oldZone;
Handle krsrc;
OSErr err;
CFragConnectionID fragID;
Ptr fragEntry, loc;
Str255 errStr;
UInt32 origSize, extOrigSize, newSize;
oldZone = GetZone();
#if !BOOTX_BUILD_INIT
SetZone(SystemZone());
#endif
krsrc = GetResource('BSTP', 1000);
if (!krsrc)
goto error;
DetachResource(krsrc);
origSize = GetHandleSize(krsrc);
extOrigSize = origSize;
extOrigSize += 0x00000FFFUL;
extOrigSize &= 0xFFFFF000UL;
mapSize += 0x00000FFFUL;
mapSize &= 0xFFFFF000UL;
/* we add a page size since we'll align things */
newSize = extOrigSize + mapSize + g_page_size;
/* we add another page since we make resident a bit more datas */
SetHandleSize(krsrc, newSize + g_page_size);
if (GetHandleSize(krsrc) != (newSize + g_page_size)) {
DisposeHandle(krsrc);
goto error;
}
HLock(krsrc);
loc = *krsrc;
loc = (Ptr)PAGE_ALIGN(loc);
if (loc != *krsrc) {
#if BOOTX_TRACE
ST_Printf(0,0,"boostrap moved from 0x%lx to 0x%lx¥n",
*krsrc, loc);
#endif
BlockMove(*krsrc, loc, origSize);
}
*outMapBegin = (UInt32*)(loc + extOrigSize);
*outTotalSize = newSize;
err = GetMemFragment(loc, origSize, "¥pbootstrap", kPrivateCFragCopy, &fragID, &fragEntry, errStr);
if (err != noErr)
{
DEBUG_ERR(err, error_prepare_bootstrap);
DisposeHandle(krsrc);
goto error;
}
SetZone(oldZone);
#if BOOTX_TRACE
ST_Printf(0,0,"boostrap entry: 0x%lx¥n", ((void **)fragEntry)[0]);
#endif
return ((void **)fragEntry)[0];
error:
SetZone(oldZone);
return NULL;
}
/* Load in the kernel image, and fix up the entry point.
*/
OSErr
load_kernel(kernel_item_t* kern_infos, UInt8* where)
{
OSErr err;
UInt32 entry;
UInt32 start;
long nb;
nb = kern_infos->file_size;
if ((err = SetFPos(kern_infos->file_ref, fsFromStart, kern_infos->offset)) != noErr
|| (err = FSRead(kern_infos->file_ref, &nb, (Ptr)where)) != noErr) {
DEBUG_ERR(err, error_read_kernel);
return err;
}
entry = (UInt32)where + kern_infos->entry;
start = *(UInt32 *)entry;
if ((start > kern_infos->file_size) || ((UInt32 *)entry)[2] != 0)
start = entry;
else
start = start + (UInt32)where;
kern_infos->entry = start;
return noErr;
}
/* Open the ramdisk file and find out how big it is */
OSErr
open_ramdisk(FSSpec *ramdiskSpec)
{
OSErr err;
err = FSpOpenDF(ramdiskSpec, fsRdPerm, &g_ramdisk_ref);
if (err != noErr)
{
DEBUG_ERR(err, error_open_ramdisk);
return err;
}
err = GetEOF(g_ramdisk_ref, (long *)&g_ramdisk_size);
if (err != noErr)
{
DEBUG_ERR(err, error_get_rd_size);
FSClose(g_ramdisk_ref);
}
return err;
}
/* Load the ramdisk file */
OSErr
load_ramdisk(UInt8* where)
{
OSErr err;
err = FSRead(g_ramdisk_ref, (long *)&g_ramdisk_size, where);
if (err != noErr)
{
DEBUG_ERR(err, error_read_ramdisk);
}
return err;
}
#if !BOOTX_BUILD_INIT
#define kFinderSig 'FNDR'
#define kSystemType 'MACS'
/* Send a restart event to the finder */
OSErr
send_restart_to_finder(void)
{
OSErr err = noErr;
ProcessSerialNumber sn;
AEDesc address;
AppleEvent theAE, reply;
err = find_finder_process(&sn);
if ( err == noErr ) err = AECreateDesc( typeProcessSerialNumber, &sn, sizeof( ProcessSerialNumber ), &address );
if ( err == noErr ) err = AECreateAppleEvent( kFinderSig, 'rest', &address, kAutoGenerateReturnID, kAnyTransactionID, &theAE);
if ( err == noErr ) err = AESend( &theAE, &reply, kAENoReply + kAECanInteract + kAECanSwitchLayer, kAENormalPriority, kAEDefaultTimeout, nil, nil );
return err;
}
/* We look for the Finder in the list of processes */
OSErr
find_finder_process(ProcessSerialNumberPtr processSN)
{
ProcessInfoRec tempInfo;
FSSpec procSpec;
Str31 processName;
OSErr myErr = noErr;
/* nul out the PSN so we're starting at the beginning of the list */
processSN->lowLongOfPSN = kNoProcess;
processSN->highLongOfPSN = kNoProcess;
/* initialize the process information record */
tempInfo.processInfoLength = sizeof(ProcessInfoRec);
tempInfo.processName = (unsigned char *)&processName;
tempInfo.processAppSpec = &procSpec;
/* loop through all the processes until we */
/* 1) find the process we want */
/* 2) error out because of some reason (usually, no more processes */
do {
myErr = GetNextProcess(processSN);
if (myErr == noErr)
GetProcessInformation(processSN, &tempInfo);
if ( tempInfo.processSignature == 'MACS' && tempInfo.processType == 'FNDR' )
break;
} while ( myErr == noErr );
return( myErr );
}
#endif
void
display_error(OSErr err, int msg, char *file, int line)
{
static Str32 errStr;
static Str32 lineStr;
static Str255 fileStr;
static Str255 msgStr;
strcpy((char *)fileStr, file);
c2pstr((char *)fileStr);
GetIndString(msgStr, string_error_codes, msg);
NumToString(err, errStr);
NumToString(line, lineStr);
ParamText(msgStr, errStr, fileStr, lineStr);
Alert(alert_error, NULL);
}
void
load_prefs(void)
{
FSSpec prefFileSpec;
short prefFileRef;
short saveResFile;
bootx_prefs_handle prefs;
OSErr err;
short itemType;
Rect itemBox;
Handle itemHandle;
Handle rsrc;
err = locate_file(string_prefs_file_names, kPreferencesFolderType, &prefFileSpec);
if (err != noErr)
return;
saveResFile = CurResFile();
prefFileRef = FSpOpenResFile(&prefFileSpec, fsRdPerm);
if (prefFileRef == -1)
return;
UseResFile(prefFileRef);
rsrc = Get1Resource('L2CR', 0);
if (rsrc)
{
if (GetHandleSize(rsrc) == 4)
{
g_L2CR_pref = true;
g_L2CR_value = *((UInt32 *)(*rsrc));
}
ReleaseResource(rsrc);
}
prefs = (bootx_prefs_handle)Get1Resource('PREF', 128);
if (prefs == NULL)
goto bail_close;
// Compare oldest compatible of prefs with version compiled with this code
if ((**prefs).compatible_version > BOOTX_PREFS_VERSION)
goto bail_release;
HLock((Handle)prefs);
g_current_choice = (**prefs).boot_choice;
g_use_ramdisk = g_have_ramdisk ? (**prefs).use_ramdisk : false;
g_video_of_only = (**prefs).video_of_only;
g_L2CR_set = (**prefs).use_l2cr_settings && g_L2CR_pref;
if (!g_boot_choices[g_current_choice][1])
g_current_choice = boot_macos;
GetDialogItem(g_dialog, field_kernel_args, &itemType, &itemHandle, &itemBox);
if (itemHandle)
SetDialogItemText(itemHandle, (**prefs).command_line);
if (g_L2CR_available)
{
if (g_L2CR_pref)
SetControlValue(g_set_L2CR_cntl, g_L2CR_set);
else
HiliteControl(g_set_L2CR_cntl, 255);
}
if ((**prefs).version >= 2)
{
GetDialogItem(g_dialog, field_root_device, &itemType, &itemHandle, &itemBox);
if (itemHandle)
SetDialogItemText(itemHandle, (**prefs).root_device);
}
if ((**prefs).version >= 4)
{
int i;
for (i=0;i<g_kernel_items_count; i++)
if (EqualString(g_kernel_items[i].file.name, (**prefs).kernel_name, false, false)) {
g_kernel_items_choice = i;
SetControlValue(g_kernel_menu, g_kernel_items[i].menu_item);
}
}
SetControlValue(g_use_ramdisk_cntl, g_use_ramdisk);
if (!g_have_ramdisk)
HiliteControl(g_use_ramdisk_cntl, 255);
SetControlValue(g_video_of_only_cntl, g_video_of_only);
setup_default_buttons();
bail_release:
HUnlock((Handle)prefs);
ReleaseResource((Handle)prefs);
bail_close:
CloseResFile(prefFileRef);
UseResFile(saveResFile);
}
void
save_prefs(void)
{
short prefsVRefNum;
long prefsParID;
static Str255 fileName;
FSSpec prefFileSpec;
short prefFileRef;
short saveResFile;
bootx_prefs_handle prefs;
OSErr err;
short itemType;
Rect itemBox;
Handle itemHandle;
int i;
// Build kernel FSSpec
err = FindFolder( kOnSystemDisk,
kPreferencesFolderType,
true,
&prefsVRefNum,
&prefsParID);
if (err != noErr)
{
DEBUG_ERR(err, error_access_prefs);
return;
}
GetIndString(fileName, string_prefs_file_names, 1);
saveResFile = CurResFile();
err = FSMakeFSSpec( prefsVRefNum, prefsParID, fileName, &prefFileSpec);
if (err == fnfErr)
{
FSpCreateResFile(&prefFileSpec, 'BooX', 'pref', smSystemScript);
err = ResError();
}
if (err != noErr)
{
DEBUG_ERR(err, error_loadcreate_prefs);
return;
}
prefFileRef = FSpOpenResFile(&prefFileSpec, fsWrPerm);
if (prefFileRef == -1)
{
err = ResError();
DEBUG_ERR(err, error_openwrite_prefs);
return;
}
prefs = (bootx_prefs_handle)Get1Resource('PREF', 128);
if (prefs == NULL)
{
prefs = (bootx_prefs_handle)NewHandle(sizeof(bootx_prefs));
if (prefs == NULL)
{
err = MemError();
DEBUG_ERR(err, error_alloc_prefs);
goto bail_close;
}
AddResource((Handle)prefs, 'PREF', 128, "¥p");
err = ResError();
if (err != noErr)
if (prefs == NULL)
{
DisposeHandle((Handle)prefs);
DEBUG_ERR(err, error_add_prefs);
goto bail_close;
}
} else
SetHandleSize((Handle)prefs, sizeof(bootx_prefs));
HLock((Handle)prefs);
memset(*prefs, 0, sizeof(bootx_prefs));
(**prefs).version = BOOTX_PREFS_VERSION;
(**prefs).compatible_version = BOOTX_PREFS_COMPATIBLE_VERSION;
(**prefs).boot_choice = g_current_choice;
(**prefs).use_ramdisk = g_use_ramdisk;
(**prefs).video_of_only = g_video_of_only;
(**prefs).use_l2cr_settings = g_L2CR_set;
GetDialogItem(g_dialog, field_kernel_args, &itemType, &itemHandle, &itemBox);
if (itemHandle)
GetDialogItemText(itemHandle, (**prefs).command_line);
GetDialogItem(g_dialog, field_root_device, &itemType, &itemHandle, &itemBox);
if (itemHandle)
GetDialogItemText(itemHandle, (**prefs).root_device);
for (i=0; i<g_kernel_items_count; i++)
if (g_kernel_items[i].menu_item == GetControlValue(g_kernel_menu))
pstrcpy((**prefs).kernel_name, g_kernel_items[i].file.name);
HUnlock((Handle)prefs);
ChangedResource((Handle)prefs);
WriteResource((Handle)prefs);
ReleaseResource((Handle)prefs);
bail_close:
CloseResFile(prefFileRef);
UseResFile(saveResFile);
FlushVol(NULL, prefsVRefNum);
}
void
do_boot_mklinux(void)
{
Handle rsrc, patch;
Str255 fileName;
OSErr err;
FSSpec prefFileSpec;
short prefFileRef, booterFileRef;
short prefsVRefNum;
long prefsParID;
long count;
// Build fake MkLinux prefs file
rsrc = Get1Resource('TEXT', text_mkboot_fake_prefs);
if (rsrc == NULL)
{
DEBUG_ERR(ResError(), error_load_mk_text);
return;
}
HNoPurge(rsrc);
patch = Get1Resource('STR#', string_mkboot_patch);
if (patch == NULL)
{
DEBUG_ERR(ResError(), error_load_mk_str);
return;
}
HNoPurge(patch);
DetachResource(patch);
err = FindFolder( kOnSystemDisk,
kPreferencesFolderType,
true,
&prefsVRefNum,
&prefsParID);
if (err != noErr)
{
DEBUG_ERR(err, error_locate_mk_prefs);
return;
}
GetIndString(fileName, string_mkboot_patch, 1);
err = FSMakeFSSpec(prefsVRefNum, prefsParID, fileName, &prefFileSpec);
if (err == fnfErr)
err = FSpCreate(&prefFileSpec, 'ttxt', 'TEXT', smSystemScript);
if (err != noErr)
{
DEBUG_ERR(err, error_open_mk_prefs);
return;
}
err = FSpOpenDF(&prefFileSpec, fsWrPerm, &prefFileRef);
if (err != noErr)
{
DEBUG_ERR(err, error_open_mk_prefs);
return;
}
err = SetEOF(prefFileRef, count = GetHandleSize(rsrc));
if (err != noErr)
{
DEBUG_ERR(err, error_write_mk_prefs);
return;
}
HLock(rsrc);
FSWrite(prefFileRef, &count, *rsrc);
FSClose(prefFileRef);
ReleaseResource(rsrc);
// Open the booter
booterFileRef = FSpOpenResFile(&g_mkboot_spec, fsRdPerm);
if (booterFileRef == -1)
{
DEBUG_ERR(ResError(), error_open_mk_booter);
return;
}
rsrc = Get1Resource('STR#', string_mkboot_patched);
if (rsrc == NULL)
{
DEBUG_ERR(ResError(), error_bad_mk_booter);
return;
}
HNoPurge(rsrc);
SetHandleSize(rsrc, GetHandleSize(patch));
BlockMoveData(*patch, *rsrc, GetHandleSize(patch));
rsrc = Get1Resource('INIT', 0);
HNoPurge(rsrc);
HLock(rsrc);
UseResFile(booterFileRef);
CallUniversalProc((UniversalProcPtr)*rsrc, kPascalStackBased);
}
Boolean
locate_mklinux(void)
{
OSErr err;
// Lookup booter
err = locate_file(string_mkboot_names, kSystemFolderType, &g_mkboot_spec);
if (err == noErr)
return true;
err = locate_file(string_mkboot_names, kExtensionFolderType, &g_mkboot_spec);
if (err == noErr)
return true;
return false;
}
#if BOOTX_LOG_MAP
static Boolean s_log_opened = false;
static short s_log_file = -1;
static void
open_log_file(void)
{
FSSpec file;
OSErr err;
if (s_log_opened)
return;
err = FSMakeFSSpec(0, 0, "¥pbootx.log", &file);
if (err == fnfErr)
err = FSpCreate(&file, 'CWIE', 'TEXT', smSystemScript);
if (err != noErr)
return;
err = FSpOpenDF(&file, fsRdWrPerm, &s_log_file);
if (err != noErr)
return;
SetFPos(s_log_file, fsFromLEOF, 0);
s_log_opened = true;
}
static void
close_log_file(void)
{
if (!s_log_opened)
return;
FSClose(s_log_file);
s_log_file = -1;
s_log_opened = false;
}
static void
log_printf(const char *fmt, ...)
{
static char s_buffer[1024];
va_list args;
long len;
if (!s_log_opened)
return;
va_start(args, fmt);
len = vsprintf(s_buffer, fmt, args);
va_end(args);
if (len)
FSWrite(s_log_file, &len, s_buffer);
}
#endif